//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.TridentModel
{
    #region Using Directives
    using System;
    using System.Collections.ObjectModel;
    using System.Windows.Media;
    using Microsoft.Research.DataLayer;
    using ErActivity = Microsoft.Research.DataLayer.Activity;
    #endregion

    /// <summary>
    /// A data model representing a category for a workflow activity. This
    /// model contains the metadata associated with that category that is
    /// helpful for a workflow designer.
    /// </summary>
    public class ActivityCategoryModel
    {
        #region Private Member Data
        /// <summary>
        /// Name of the Category Model.
        /// </summary>
        private string name;

        /// <summary>
        /// Label of the Category Model.
        /// </summary>
        private string label;

        /// <summary>
        /// Id of the Category Model.
        /// </summary>
        private string path;

        /// <summary>
        /// Description of the category Model.
        /// </summary>
        private string description;

        /// <summary>
        /// Whether the category is editable or not.
        /// </summary>
        private bool isEditable = true;

        /// <summary>
        /// Edit Color.
        /// </summary>
        private Color editColor = Colors.Gray;

        /// <summary>
        /// Is edit color Default.
        /// </summary>
        private bool isEditColorDefault = true;

        /// <summary>
        /// Imgae source of the icon.
        /// </summary>
        private ImageSource iconImageSource;

        /// <summary>
        /// Parent category Model.
        /// </summary>
        private ActivityCategoryModel parent;

        /// <summary>
        /// Sub category Models.
        /// </summary>
        private Collection<ActivityCategoryModel> subcats = new Collection<ActivityCategoryModel>();

        /// <summary>
        /// Activities under this Category Model.
        /// </summary>
        private Collection<ActivityMetadata> activities = new Collection<ActivityMetadata>();

        #endregion

        #region Constructors
        /// <summary>
        /// Create a category given an identification string. For more about
        /// the ID string, see the comments in that property definition.
        /// </summary>
        public ActivityCategoryModel(string id)
        {
            this.path = id;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="category"></param>
        public ActivityCategoryModel(Namespace category)
        {
            #region Validation of Arguments
            if (null == category)
            {
                throw new ArgumentNullException("category");
            }
            #endregion

            // Get the Name.
            this.Name = category.Name;

            // Set the id to name.
            this.path = category.Name;

            this.Id = (category as IObject).ID;

            this.isEditable = category.IsEditable;

            // recurse through the children and create models.
            if (category.Children != null)
            {
                foreach (Namespace catChild in category.Children)
                {
                    ActivityCategoryModel catModelChild = new ActivityCategoryModel(catChild);
                    catModelChild.Parent = this;
                    this.Categories.Add(catModelChild);
                }
            }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Create Uncategorized category.
        /// </summary>
        /// <returns>ActivityCategoryModel object.</returns>
        public static ActivityCategoryModel CreateUncategorizedCategory()
        {
            ActivityCategoryModel result = null;
            result = new ActivityCategoryModel("Uncategorized");
            result.Name = "Uncategorized";
            result.IsEditable = false;
            result.Description = "A placeholder category for workflow activities that have not been assigned a proper category of their own";

            return result;
        }
        #endregion

        #region Properties
        /// <summary>
        /// A descriptive workflowName of the category. This should be a short but
        /// descriptive workflowName identifying the function of the activities that
        /// fall in this category.
        /// </summary>
        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                this.name = value;
            }
        }

        /// <summary>
        /// A descriptive workflowName of the category that is specifically shortened
        /// to fit all common uses inside a visual design tool. If the Label is
        /// not provided, the Name will be returned.
        /// </summary>
        public string Label
        {
            get
            {
                if (String.IsNullOrEmpty(label))
                    return this.name;
                return this.label;
            }
            set
            {
                this.label = value;
            }
        }

        /// <summary>
        /// A full description of the category.
        /// </summary>
        public string Description
        {
            get
            {
                return this.description;
            }
            set
            {
                this.description = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is editable.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is editable; otherwise, <c>false</c>.
        /// </value>
        public bool IsEditable
        {
            get
            {
                return this.isEditable;
            }
            set
            {
                this.isEditable = value;
            }
        }

        /// <summary>
        /// An identification meant for use in quickly identifying a path
        /// through the category tree to a particular category. This ID
        /// should be unique amongst its siblings. It also can not contain
        /// the '/' character.
        /// </summary>
        public string Path
        {
            get
            {
                return this.path;
            }
            set
            {
                if (value.Contains("/"))
                    throw new ArgumentException("Cateogry IDs can not contain '/'");
                this.path = value;
            }
        }

        /// <summary>
        /// The parent category of this category. If this is a top level category, then
        /// null will be returned.
        /// </summary>
        public ActivityCategoryModel Parent
        {
            get
            {
                return this.parent;
            }
            set
            {
                this.parent = value;
            }
        }

        /// <summary>
        /// Returns the root category above this category. If this is a top level category
        /// in the heirarchy, then this category is returned.
        /// </summary>
        public ActivityCategoryModel RootCategory
        {
            get
            {
                if (this.parent == null)
                    return this;

                ActivityCategoryModel ancestor = this.parent;
                while (ancestor.parent != null)
                    ancestor = ancestor.parent;

                return ancestor;
            }
        }

        /// <summary>
        /// The color used by the editor to give a visual clue about the category.
        /// The colors are arbitrary, but can be helpful for usability.
        /// </summary>
        public Color PrimaryEditorColor
        {
            get
            {
                if (isEditColorDefault && parent != null)
                {
                    return parent.PrimaryEditorColor;
                }
                return this.editColor;
            }
            set
            {
                isEditColorDefault = false;
                this.editColor = value;
            }
        }

        /// <summary>
        /// A lighter version of the PrimaryEditorColor
        /// </summary>
        public Color LightEditorColor
        {
            get
            {
                return Color.Multiply(PrimaryEditorColor, 0.3f);
            }
        }

        /// <summary>
        /// Gets or sets the ImageSource for an icon that symbolizes the function of this category. 
        /// If an image source is not specified, it will try and inherit that image source from 
        /// it's parent category. If there is no parent category and no image source has been 
        /// defined, then null is returned.
        /// </summary>
        public ImageSource IconImageSource
        {
            get
            {
                if (iconImageSource == null && Parent != null)
                {
                    return Parent.IconImageSource;
                }
                return this.iconImageSource;
            }
            set
            {
                this.iconImageSource = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public Guid Id { get; set; }

        /// <summary>
        /// The children categories (ie subcategories) that fall under this category.
        /// </summary>
        public Collection<ActivityCategoryModel> Categories
        {
            get
            {
                return this.subcats;
            }
        }

        /// <summary>
        /// The children activities that fall under this category.
        /// </summary>
        public Collection<ActivityMetadata> Activities
        {
            get
            {
                return this.activities;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool ActivitiesLoaded { get; set; }
        #endregion
    }
}
